package gulimall.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import gulimall.constant.ProductConstant;
import gulimall.constant.ProductConstant.AttrEnum;
import gulimall.entity.Attr;
import gulimall.entity.AttrAttrgroupRelation;
import gulimall.entity.AttrGroup;
import gulimall.entity.Category;
import gulimall.mapper.AttrAttrgroupRelationMapper;
import gulimall.mapper.AttrGroupMapper;
import gulimall.mapper.AttrMapper;
import gulimall.service.*;
import gulimall.utils.PageUtils;
import gulimall.utils.Query;
import gulimall.vo.AttrRespVo;
import gulimall.vo.AttrVo;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrMapper, Attr> implements AttrService {

    @Resource
    private AttrAttrgroupRelationService relationService;

    @Resource
    private ICategoryService categoryService;

    @Resource
    private IAttrGroupService attrGroupService;

    @Resource
    private AttrService attrService;

    @Resource
    private AttrGroupMapper attrGroupMapper;

    @Resource
    private AttrMapper attrMapper;

    @Resource
    private AttrAttrgroupRelationMapper relationMapper;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<Attr> page = this.page(
                new Query<Attr>().getPage(params),
                new QueryWrapper<Attr>()
        );

        return new PageUtils(page);
    }

    @Transactional(isolation = Isolation.REPEATABLE_READ)
    @Override
    public void saveAttr(AttrVo attrVo) {
        Attr attrPo = new Attr();
        BeanUtils.copyProperties(attrVo, attrPo);//把attrVo中的同名属性值赋值给attrPo
        //1.保存基本数据
        /**
         * mp自带的方法会自动返回新增后的自增主键id
         * 前提是主键自增列被注解标注：
         * @TableId(value = "attr_id", type = IdType.AUTO)
         * private Long attrId;
         * 其他两种方式见gulimall业务笔记
         */
        baseMapper.insert(attrPo);
        if (attrVo.getAttrType() == AttrEnum.ATTR_TYPE_BASE.getCode()) {//如果是基本属性才需要在关系表中添加attrId和attrGroupId的关系
            //2.保存关联关系(属性分组表中的字段)
            AttrAttrgroupRelation relation = new AttrAttrgroupRelation();
            relation.setAttrId(attrPo.getAttrId());
            relation.setAttrGroupId(attrVo.getAttrGroupId());
            relationService.save(relation);
        }
    }

    /**
     * 查询规格参数和销售属性列表，并做分页
     *
     * @param params    分页参数
     * @param catelogId 品牌分类id
     * @param attrType
     * @return
     */
    @Override
    @Transactional
    public PageUtils queryBaseAttrPage(Map<String, Object> params, Long catelogId, String attrType) {
        QueryWrapper<Attr> queryWrapper = new QueryWrapper<>();

        //当属性类型是base表示是基本属性(1)，否则就是销售属性(0)
        queryWrapper.lambda()
                .eq(Attr::getAttrType, "base".equalsIgnoreCase(attrType)
                        ? AttrEnum.ATTR_TYPE_BASE.getCode()
                        : AttrEnum.ATTR_TYPE_SALE.getCode()
                );

        if (catelogId != 0) {//表示不是查询所有
            queryWrapper.lambda()
                    //当检索内容刚好是catelogId时进行匹配
                    .eq(Attr::getCatelogId, catelogId);
        }

        String key = (String) params.get("key");
        if (StringUtils.isNotBlank(key)) {
            queryWrapper.lambda().and(wrapper -> {
                //匹配分组id或分组名称
                wrapper.eq(Attr::getAttrId, key).or().like(Attr::getAttrName, key);
            });
        }

        IPage<Attr> page = this.page(
                new Query<Attr>().getPage(params),
                queryWrapper
        );
        PageUtils pageUtils = new PageUtils(page);

        List<Attr> records = page.getRecords();
        List<AttrRespVo> respVoList = records.stream().map(attr -> {
            AttrRespVo attrRespVo = new AttrRespVo();
            //1.把attr中的所有同名属性值赋值给attrRespVo
            BeanUtils.copyProperties(attr, attrRespVo);

            //2.获取所属分类名称
            Category category = categoryService.getById(attr.getCatelogId());
            if (category != null) {
                //设置所属分类名称
                attrRespVo.setCatelogName(category.getName());
            }

            if ("base".equalsIgnoreCase(attrType)) {//如果是规格参数，则需要设置属性分组，销售属性不需要
                //3.获取属性分组名称
                //通过attrId获取AttrAttrgroupRelation对象
                AttrAttrgroupRelation relation = relationService.getOne(new QueryWrapper<AttrAttrgroupRelation>()
                        .lambda().eq(AttrAttrgroupRelation::getAttrId, attr.getAttrId())
                );
                if (relation != null) {
                    //获取attrGroupId
                    Long attrGroupId = relation.getAttrGroupId();
                    if (attrGroupId != null) {
                        //获取属性分组attrGroup对象
                        AttrGroup attrGroup = attrGroupService.getById(attrGroupId);
                        //设置属性分组
                        attrRespVo.setGroupName(attrGroup.getAttrGroupName());
                    }
                }
            }
            return attrRespVo;
        }).collect(Collectors.toList());

        pageUtils.setList(respVoList);

        return pageUtils;
    }

    /**
     * 通过attrId获取属性的具体信息，包括属性的分组id=>attrGroupId和分类的完整路径catelogPath
     *
     * @param attrId
     * @return 返回一个AttrRespVo对象
     */
    @Override
    public AttrRespVo getAttrInfo(Long attrId) {
        Attr attr = this.getById(attrId);
        AttrRespVo attrRespVo = new AttrRespVo();
        BeanUtils.copyProperties(attr, attrRespVo);

        //如果是规格参数(基本属性)就需要获取分组信息，销售属性就不需要
        if (attr.getAttrType() == AttrEnum.ATTR_TYPE_BASE.getCode()) {
            //1.获取attrGroupId
            AttrAttrgroupRelation relation = relationService.getOne(
                    new QueryWrapper<AttrAttrgroupRelation>().lambda()
                            .eq(AttrAttrgroupRelation::getAttrId, attrId)
            );
            if (relation != null) {
                Long attrGroupId = relation.getAttrGroupId();
                attrRespVo.setAttrGroupId(attrGroupId);
            }
        }
        //2.获取分类完整路径
        List<Long> catIds = categoryService.getCatIdsByLeaf(attr.getCatelogId());
        attrRespVo.setCatelogPath(catIds);

        return attrRespVo;
    }

    /**
     * 修改属性详情
     */
    @Override
    @Transactional
    public void updateAttrById(AttrVo attrVo) {
        Attr attr = new Attr();
        BeanUtils.copyProperties(attrVo, attr);

        //1.修改自身
        baseMapper.updateById(attr);

        if (attrVo.getAttrType() == AttrEnum.ATTR_TYPE_BASE.getCode()) {//如果是基本属性才需要修改关系表中的attrGroupId
            //2.修改关联，修改属性分组id=>attrGroupId
            //判断关系表中是否有当前attrId对应的数据，如果有就修改，没有就新增
            long count = relationService.count(new QueryWrapper<AttrAttrgroupRelation>()
                    .lambda()
                    .eq(AttrAttrgroupRelation::getAttrId, attr.getAttrId())
            );

            AttrAttrgroupRelation relation = new AttrAttrgroupRelation();
            if (count > 0) {
                //设置要修改的值
                relation.setAttrGroupId(attrVo.getAttrGroupId());
                relationService.update(relation, new UpdateWrapper<AttrAttrgroupRelation>()
                        .lambda()
                        .eq(AttrAttrgroupRelation::getAttrId, attr.getAttrId())
                );
            } else {
                //在关系表新增一条数据(属性attr和属性分组attrGroup)
                relation.setAttrId(attrVo.getAttrId());
                relation.setAttrGroupId(attrVo.getAttrGroupId());
                relationService.save(relation);
            }
        }
    }

    /**
     * 获取属性分组的关联的所有属性
     *
     * @param attrgroupId 属性分组id
     * @return
     */
    @Override
    public List<Attr> getRelationAttr(Long attrgroupId) {
        //获取attrgroupId对应的所有relation
        List<AttrAttrgroupRelation> relations = relationService.list(new QueryWrapper<AttrAttrgroupRelation>()
                .lambda().eq(AttrAttrgroupRelation::getAttrGroupId, attrgroupId)
        );
        //通过attrId获取attr对象
        List<Attr> attrList = relations.stream().map(relation -> {
            return attrService.getById(relation.getAttrId());
        }).collect(Collectors.toList());
        return attrList;
    }

    /**
     * 获取属性分组里面还没有关联的本分类里面的其他基本属性，方便添加新的关联
     *
     * @param params
     * @param attrgroupId
     * @return
     */
    @Override
    public PageUtils getNoRelationAttr(Map<String, Object> params, String attrgroupId) {
        //1.根据attrGroupId查询出所属分类id=>catelogId
        AttrGroup attrGroup = attrGroupMapper.selectById(attrgroupId);
        Long catelogId = attrGroup.getCatelogId();

        //2.查询出当前分类catelogId对应的所有分组
        List<AttrGroup> attrGroups = attrGroupMapper.selectList(new QueryWrapper<AttrGroup>()
                .lambda().eq(AttrGroup::getCatelogId, catelogId)
        );
        List<Long> groupIds = attrGroups.stream().map(AttrGroup::getAttrGroupId).collect(Collectors.toList());

        //3.查询出这些分组对应的属性(这些都是已关联的属性,都存在于relation表中)
        List<AttrAttrgroupRelation> relations = relationMapper.selectList(new QueryWrapper<AttrAttrgroupRelation>()
                .lambda().in(AttrAttrgroupRelation::getAttrGroupId, groupIds)
        );
        //3.1从attrIds去除特殊情况(attrId存在，但是attrGroupId是null的情况)
        //导致这种情况的原因：在新增规格参数时没有选所属分组导致
        relations.removeAll(attrMapper.selectByGroupIsNull(catelogId));
        List<Long> attrIds = relations.stream().map(AttrAttrgroupRelation::getAttrId).collect(Collectors.toList());

        //4.从当前分类的所有属性中移除掉这些已关联的属性，就可以得到没有关联的这些属性
        //创建一个筛选最终需要的Attr的QueryWrapper
        QueryWrapper<Attr> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(Attr::getCatelogId, catelogId) //匹配当前分类id
                .eq(Attr::getAttrType, AttrEnum.ATTR_TYPE_BASE.getCode());//匹配当前分类下的规格参数
        if (attrIds.size() > 0) {
            queryWrapper.lambda().notIn(Attr::getAttrId, attrIds);
        }

        //5.属性名关键字匹配
        String key = (String) params.get("key");
        if (StringUtils.isNotBlank(key)) {
            queryWrapper.and(wrapper -> {
                wrapper.lambda()
                        .eq(Attr::getAttrId, key)
                        .or().like(Attr::getAttrName, key);
            });

        }

        IPage<Attr> page = this.page(
                new Query<Attr>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }
}